iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 24
0
Software Development

邁向專業軟體工程師必修的英文課系列 第 24

Day 24 – [動詞四] 迴圈 – 你讓程式在系統裡空轉了嗎?

  • 分享至 

  • xImage
  •  

迴圈是程式的基本語法之一,每個程式語言都會有迴圈。大致上分成兩種

  1. For loop 型
  2. Do-while型

今天這篇不講語法,講一些比較深入要去探討的問題:

Big-O

現在很多工程師可能透過很多管道入行,有自學的,有拜師的,有上課的,有boot camp的,當然也有本科生繼續留在這個行業裡打拼。然而,知道Big O的應該就沒那麼多了。

什麼是Big-O?可以把它想像成一個衡量程式複雜度的指標,之所以叫Big的原因是因為他是指標的上指標:所以也有Small O以及其他各種的Notation。而這個指標會應用在兩個維度上:空間(記憶體)及時間(執行時間)
Big-O的介紹很多,我在這裡就不再贅述了。

為什麼要有這個指標?在過去那個CPU和RAM都很貴的年代,工程師追求的是用最便宜的方法執行程式,所有的工程師無不想方設法去找出有效率的方式來執行程式。

cc https://cs.techruto.com/2017/05/big-oh-notation-theory-and-calculation.html
為什麼要在這裡提Big-O?因為一個迴圈,就是一個級數的差別,其實也不難想像,因為迴圈的設計就是在原地做同樣的事情N遍,而如果有兩層迴圈,那就要在原地做N*M遍,以此類推。

就因為迴圈是那麼的容易,但又那麼的昂貴,在使用迴圈時要更加注意:是否真的有必要使用迴圈?有沒有更好的方法可以取代?例如用HashSet取代Array,用Binary Search取代原本的逐一搜尋,把重要的值存在變數裡….等等。

cc http://blog.benoitvallon.com/data-structures-in-javascript/data-structures-in-javascript/
熟悉愈多種語言提供的資料結構對工程師愈有利,如果一個工程師只會用Array或者List,其實是相當不足的:這己經是一個什麼都東西準備好隨時可以用的時代,應該透過更多管道讓自己強壯起來。

Off-by-one Error

在寫迴圈時,最常碰到的錯誤,就叫Off-By-One。什麼是Off-By-One?就是迴圈在計數時,多算了一個,而造成程式在執行時發生錯誤,例如:

var array = new int[10];
for(int i = 0 ; I <= array.Length ; i++){
     Show(array[i]);
}

這段程式會嘗試印出整個陣列,但因為計數器的範圍設定錯誤,會跑到i[10],然後拋出index out of range exception。
看似很蠢的錯誤,但卻經常發生。
這個其實很難避免,就算是手指有著肌肉記憶也常會多打出錯誤的條件。比較好的做法是:利用比較新的的語法,例如foreach或者LINQ來處理迴圈,避免OBOE。

foreach(var element in array){
    Show(element);
}

有沒有trade off?當然有,效能會有所影響,但以語法來看,我會建議如果沒有一定需要去計數的話,還是使用foreach比較好。

SDK的隱藏成本

前面講到工程師應該要了解資料結構,除了知道有那些外,還要注意使用上是否有隱藏了一些效能上的問題。
在前面我們說到了Big-O,他有一個很簡單的計算方法,就是看眼前的迴圈有幾個。而SDK可能把這方面的資訊包裝了起來,例如:

            HashSet<string> hashSet = new HashSet<string>();
            hashSet.Contains("HelloWorld");

好像沒有迴圈對吧,但如果查看Contains的實作方法:

    public bool Contains(T item)
    {
      if (this.m_buckets != null)
      {
        int hashCode = this.InternalGetHashCode(item);
        for (int index = this.m_buckets[hashCode % this.m_buckets.Length] - 1; index >= 0; index = this.m_slots[index].next)
        {
          if (this.m_slots[index].hashCode == hashCode && this.m_comparer.Equals(this.m_slots[index].value, item))
            return true;
        }
      }
      return false;
    }

它還是一個迴圈,雖然效能上還是有調整過(例如它是使用bucket,所以搜尋的範圍比較小),但這個隱藏成本經常被忽略。
除此之外,有些像LINQ的工具也有很多方便又神奇的功能可以使用,然而使用它可能要付出更大的成本:無論是時間或空間。不是不能使用,而是使用時一定要先了解使用方法,避免眼前看起來很漂亮,但實際卻折損了效能。

以前我聽說數學系的把高等微積分當成小說在看,我覺得程式設計師應該把資料結構與演算法當小說看,總會看出一些有趣的東西。
如果不想看那麼難的東西,可以看看這本書:雖然是為面試準備的,但其實裡面很多有趣的技術可以學習。


上一篇
Day 23 - [感嘆詞] 寫出讓人了解的訊息
下一篇
Day 25 – [形容詞三] Equal - 怎麼等號愈來愈多了?
系列文
邁向專業軟體工程師必修的英文課30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言